package ThreadingSafety;
/*
/**
 * Date: 2022-09-11 8月14 02:56:22 的课程内容 :
 * Time: 15:38
 *
 * 线程安全问题: 多线程中的 重点 和 难点 ~~
 *     线程安全的意思,在多线程各种随机调度顺序下,不会出现bug,都能符合预期的方式来执行~
 *     相反,如果在在多线程各种随机调度顺序下,会出现bug, 就认为是线程不安全. (课程大概 03:00:00 时就举了一个典型的线程不安全的例子 ).
 *
 * 线程不安全的原因 : 在 9月6  00:52:00时有讲解..  [原因要牢记!!!]
 *                 1. 抢占式执行(线程不安全的万恶之源, 罪魁祸首)
 *                 2. 多线程 修改 同一个 变量
 *                 3. 修改操作不是原子的 [解决线程安全问题, 最常见的办法, 就是从此入手!] -> "并发" 改为 "串行"
 *                 4. 内存可见性问题.[JVM的代码优化引入的bug]
 *                 5. 指令重排序
 *                 6. ......
 *
 *   以下代码存在线程不安全, 可通过特殊手段让 count++ 变成原子的 : 加锁!!!
 *   在 count++ 之前加锁, 在 count++ 之后再解锁~~
 *      在加锁和解锁之间, 别的线程时修改不了的.
 *   Java 代码中, 进行加锁使用 synchronized 关键字 [会写会读会背] -> [特性: 互斥, 可重入]
 *      1. synchronized 可修饰方法
 *      2. synchronized 可修饰代码块.
 *      3. 修饰静态方法. 锁对象相当于 类对象(不是锁整个类).
 *      4. 具体代码演示在 9月6 00:34:00左右的课程 讲解.
 *      5. 死锁 问题, 在 Demo14Child 中讲解
 */

/*一个典型的线程不安全的例子
class Counter {
    public int count = 0;
    /*
    //存在 线程安全问题 的写法 :
    public void increase() {
        count++;
    }
     */

    /*
    // 使用 synchronised 关键字 最基本的 用法:
    //      修饰一个 普通方法: 进入方法就会加锁, 方法执行完毕就会解锁
    public synchronized void increase() {
        count++;
    }


    static private Object locker = new Object();

    // synchronised 修饰代码块 :
    public void increase() {
        synchronized(Counter.class) {
            // () 里要填 要加锁的那个对象.(被用来枷锁的对象,简称为"锁对象")
            // java 中任意对象都可以作为锁对象,这一点和其他的编程语言差别很大.
            // 一个 synchronized 只能锁一个对象.
            // 那么 () 里该怎么填呢 ?
            //  1. this. -> 针对当前对象加锁, 谁调用 increase() 方法,谁就是 this.
            //  2. 任意对象.
            count++;
        }
    }
}

public class TestDemo14 {

    private static Counter counter = new Counter();
    private static Counter counter2 = new Counter();

    public static void main(String[] args) throws InterruptedException {
        // 搞两个线程, 每个线程都对 count 进行5w 次自增
        // 预期结果就是 10w

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5_0000; i++) {
                counter.increase();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5_0000; i++) {
                counter2.increase();
            }
        });
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("count: " + counter.count);
    }
}
*/